package mapper

import (
	"context"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	constans "mall/services/product/rpc/consts"
	"mall/services/product/rpc/internal/domain/bo"
	"mall/services/product/rpc/internal/initialize/mysql"
	"mall/services/product/rpc/internal/mapper/entity"
	"time"
)

var brandAllColumn = "brand_id, create_time, update_time, name, `desc`, img_url, first_letter, seq, status"

type BrandMapper struct {
	ctx context.Context
}

func NewBrandMapper(ctx context.Context) *BrandMapper {
	return &BrandMapper{ctx: ctx}
}

func (m *BrandMapper) SelectCountCtx(db *gorm.DB, brandBO bo.BrandBO) (totalCount int64, err error) {
	// 监控
	_, span := mysql.StartSpan(m.ctx, "BrandMapper#SelectCountCtx")
	defer func() {
		mysql.EndSpan(span, err)
	}()
	tx := db.Session(&gorm.Session{SkipDefaultTransaction: true})

	var total int64
	brandEntity := entity.BrandEntity{}
	tx = tx.Select(brandAllColumn).Table(brandEntity.TableName())
	m.getAllWhereSql(tx, brandBO)
	tx.Count(&total)
	return total, tx.Error
}

func (m *BrandMapper) SelectOneCtx(db *gorm.DB, brandBO bo.BrandBO) (returnEntity entity.BrandEntity, err error) {
	// 监控
	_, span := mysql.StartSpan(m.ctx, "BrandMapper#SelectOneCtx")
	defer func() {
		mysql.EndSpan(span, err)
	}()
	tx := db.Session(&gorm.Session{SkipDefaultTransaction: true})

	brandEntity := entity.BrandEntity{}
	tx = tx.Select(brandAllColumn).Table(brandEntity.TableName())
	m.getAllWhereSql(tx, brandBO)
	tx.First(&brandEntity)
	if tx.Error == nil || tx.Error.Error() == "record not found" {
		return brandEntity, nil
	}
	return brandEntity, tx.Error
}

func (m *BrandMapper) SelectListCtx(db *gorm.DB, brandBO bo.BrandBO) (returnEntity []entity.BrandEntity, err error) {
	// 监控
	_, span := mysql.StartSpan(m.ctx, "BrandMapper#SelectListCtx")
	defer func() {
		mysql.EndSpan(span, err)
	}()
	tx := db.Session(&gorm.Session{SkipDefaultTransaction: true})
	var brandEntityArr []entity.BrandEntity
	tx = tx.Select(brandAllColumn).Table("brand")
	m.getAllWhereSql(tx, brandBO)
	tx = tx.Find(&brandEntityArr)
	return brandEntityArr, tx.Error
}

func (m *BrandMapper) getAllWhereSql(db *gorm.DB, brandBO bo.BrandBO) {
	if brandBO.BrandId > 0 {
		db.Where("brand_id = ?", brandBO.BrandId)
	}
	if len(brandBO.Name) > 0 {
		db.Where("name = ?", brandBO.Name)
	}
	if len(brandBO.NameAllLike) > 0 {
		db.Where("name like ?", "%"+brandBO.NameAllLike+"%")
	}
	if len(brandBO.Desc) > 0 {
		db.Where("desc = ?", brandBO.Desc)
	}
	if len(brandBO.ImgUrl) > 0 {
		db.Where("img_url = ?", brandBO.ImgUrl)
	}
	if len(brandBO.FirstLetter) > 0 {
		db.Where("first_letter = ?", brandBO.FirstLetter)
	}
	if brandBO.Seq > 0 {
		db.Where("seq = ?", brandBO.Seq)
	}
	if brandBO.Status != 0 {
		db.Where("status = ?", brandBO.Status)
	}
	if brandBO.NeStatus != 0 {
		db.Where("status != ?", brandBO.NeStatus)
	}
	if len(brandBO.StartTime) > 0 {
		db.Where("create_time = ?", brandBO.StartTime)
	}
	if len(brandBO.EndTime) > 0 {
		db.Where("create_time = ?", brandBO.EndTime)
	}
}

func (m *BrandMapper) InsertCtx(engin *gorm.DB, brandEntity *entity.BrandEntity) (err error) {
	// 监控
	_, span := mysql.StartSpan(m.ctx, "BrandMapper#InsertCtx")
	defer func() {
		mysql.EndSpan(span, err)
	}()
	tx := engin.Create(brandEntity)
	return tx.Error
}

func (m *BrandMapper) DeleteCtx(engin *gorm.DB, brandIdArr []int64) (err error) {
	// 监控
	_, span := mysql.StartSpan(m.ctx, "BrandMapper#DeleteCtx")
	defer func() {
		mysql.EndSpan(span, err)
	}()
	brandEntity := entity.BrandEntity{Status: constans.Delete, UpdateTime: time.Now()}
	tx := engin.Table("brand").Where("brand_id in ?", brandIdArr).Omit("brand_id").
		UpdateColumns(brandEntity)
	return tx.Error
}

func (m *BrandMapper) UpdateCtx(engin *gorm.DB, builderEntity *entity.BrandEntity) (err error) {
	// 监控
	_, span := mysql.StartSpan(m.ctx, "BrandMapper#UpdateCtx")
	defer func() {
		mysql.EndSpan(span, err)
	}()
	tx := engin.Where("brand_id = ?", builderEntity.BrandId).Omit("brand_id").
		UpdateColumns(builderEntity)
	return tx.Error
}

func (m *BrandMapper) SelectPageListCtx(db *gorm.DB, brandBO bo.BrandBO) (returnArr []entity.BrandEntity, err error) {
	// 监控
	_, span := mysql.StartSpan(m.ctx, "BrandMapper#SelectPageListCtx")
	defer func() {
		mysql.EndSpan(span, err)
	}()
	tx := db.Session(&gorm.Session{SkipDefaultTransaction: true})
	var brandEntityArr []entity.BrandEntity
	if brandBO.PageSize > 0 {
		tx = tx.Select(brandAllColumn).Table("brand").Offset(brandBO.StartIndex)
		m.builderWhereAndSorts(tx, brandBO)
		tx = tx.Limit(brandBO.PageSize).Find(&brandEntityArr)
	} else {
		tx.Select(spuAllColumn).Table("brand")
		m.builderWhereAndSorts(tx, brandBO)
		tx = tx.Find(&brandEntityArr)
	}
	// return obj
	return brandEntityArr, nil
}

func (m *BrandMapper) builderWhereAndSorts(tx *gorm.DB, brandBO bo.BrandBO) {
	// builder where
	m.getAllWhereSql(tx, brandBO)
	// process order
	if len(brandBO.Sorts) > 0 {
		for _, v := range brandBO.Sorts {
			orderByColumn := clause.OrderByColumn{}
			orderByColumn.Column = clause.Column{Name: v.FiledName, Table: "brand"}
			if v.Sort == "asc" {
				orderByColumn.Desc = false
			} else {
				orderByColumn.Desc = true
			}
			tx.Order(orderByColumn)
		}
	}
}
